home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / wordwrap.c < prev   
C/C++ Source or Header  |  1994-06-05  |  31KB  |  997 lines

  1. /*
  2.  * This module contains the word wrap and format paragraph functions.  The
  3.  *  right_justify( ) function is based on the spread function in _Software
  4.  *  Tools_ by Brian Kernighan and P J Plauger.  My version of the spread
  5.  *  function handles lines with extra blanks in the text, e.g. two blanks
  6.  *  after periods.  All of the other word processing routines are original
  7.  *  and written by me, Frank, and are not guaranteed to work as designed.
  8.  *
  9.  * See:
  10.  *
  11.  *   Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
  12.  *    Wesly, Reading, Mass., 1976, Section 7.7, "Right Margin Justification",
  13.  *    pp 239-242.  ISBN 0-201-03669-X.
  14.  *
  15.  * Note: right margin justification was added in TDE 2.2.
  16.  *
  17.  * New editor name:  TDE, the Thomson-Davis Editor.
  18.  * Author:           Frank Davis
  19.  * Date:             June 5, 1991, version 1.0
  20.  * Date:             July 29, 1991, version 1.1
  21.  * Date:             October 5, 1991, version 1.2
  22.  * Date:             January 20, 1992, version 1.3
  23.  * Date:             February 17, 1992, version 1.4
  24.  * Date:             April 1, 1992, version 1.5
  25.  * Date:             June 5, 1992, version 2.0
  26.  * Date:             October 31, 1992, version 2.1
  27.  * Date:             April 1, 1993, version 2.2
  28.  * Date:             June 5, 1993, version 3.0
  29.  * Date:             August 29, 1993, version 3.1
  30.  * Date:             June 5, 1994, version 4.0
  31.  *
  32.  * This code is released into the public domain, Frank Davis.
  33.  * You may distribute it freely.
  34.  */
  35.  
  36. #include "tdestr.h"     /* global variables definitions */
  37. #include "common.h"     /* external global variable declarations */
  38. #include "define.h"
  39. #include "tdefunc.h"
  40.  
  41.  
  42. /*
  43.  * Name:    find_left_margin
  44.  * Purpose: find left margin depending on word wrap mode
  45.  * Date:    June 5, 1992
  46.  * Passed:  ll:         node pointer to current line
  47.  *          wrap_mode:  current word wrap mode
  48.  * Notes:   the algorithm used to figure the indent column was yanked out
  49.  *           of the insert_newline( ) function and was made into a more
  50.  *           general algorithm for figuring the left margin irregardless
  51.  *           of word wrap or indent mode.  when in the DYNAMIC_WRAP mode,
  52.  *           the user don't have to keep changing the left margin when
  53.  *           special indentation is needed.
  54.  */
  55. int  find_left_margin( line_list_ptr ll, int wrap_mode )
  56. {
  57. register int lm;
  58. int  len;
  59. text_ptr source;
  60.  
  61.    if (wrap_mode == FIXED_WRAP) {
  62.       /*
  63.        * for FIXED_WRAP mode, the left and paragraph margins are determined
  64.        *   from the master mode structure.
  65.        */
  66.       if (g_status.copied) {
  67.          source = (text_ptr)g_status.line_buff;
  68.          len    = g_status.line_buff_len;
  69.       } else {
  70.          if (ll->prev != NULL) {
  71.             source = ll->prev->line;
  72.             len    = ll->prev->len;
  73.          } else {
  74.             source = NULL;
  75.             len    = 0;
  76.          }
  77.       }
  78.       if (source == NULL)
  79.          lm = mode.parg_margin;
  80.       else if (find_end( source, len ) == 0)
  81.          lm = mode.parg_margin;
  82.       else
  83.          lm = mode.left_margin;
  84.    } else {
  85.       /*
  86.        * for Indent and DYNAMIC_WRAP modes, the left margin is determined
  87.        *  from the first non blank line above the cursor.
  88.        */
  89.       if (g_status.copied == TRUE) {
  90.          source = (text_ptr)g_status.line_buff;
  91.          len    = g_status.line_buff_len;
  92.       } else {
  93.          source = ll->line;
  94.          len    = ll->len;
  95.       }
  96.       lm = first_non_blank( source, len );
  97.       if (is_line_blank( source, len ) && ll->prev != NULL) {
  98.          for (ll=ll->prev; ll != NULL; ll=ll->prev) {
  99.             lm = first_non_blank( ll->line, ll->len );
  100.             if (!is_line_blank( ll->line, ll->len ))
  101.                break;
  102.          }
  103.       }
  104.    }
  105.    return( lm );
  106. }
  107.  
  108.  
  109. /*
  110.  * Name:    word_wrap
  111.  * Purpose: make sure lines don't get longer than right margin
  112.  * Date:    November 27, 1991
  113.  * Passed:  window:  pointer to current window
  114.  * Notes:   rcol, lm, rm, pm all start counting at zero.
  115.  *          len (line length) starts counting at 1.
  116.  *
  117.  *          when we compare margins and line lengths, we either have to
  118.  *          add one to the margins or subtract one from the len.  I add
  119.  *          one to the margins.
  120.  */
  121. void word_wrap( TDE_WIN *window )
  122. {
  123. int  c;                 /* character the user just entered. */
  124. register int len;       /* length of current line */
  125. int  i;                 /* padding spaces required */
  126. line_list_ptr p;        /* line above wrapped line */
  127. int  rcol;
  128. int  lm;
  129. int  rm;
  130. int  side;
  131. register TDE_WIN *win;          /* put window pointer in a register */
  132.  
  133.    win = window;
  134.  
  135.    /*
  136.     * set up a few local variables.
  137.     */
  138.    c = g_status.key_pressed;
  139.    rcol = win->rcol;
  140.    copy_line( win->ll );
  141.    detab_linebuff( );
  142.  
  143.    /*
  144.     * always start the right margin justification on the right side
  145.     *  at the beginning of paragraphs.  then, alternate with left margin.
  146.     */
  147.    side = 1;
  148.    p = win->ll->prev;
  149.    while (p != NULL  &&  !is_line_blank( p->line, p->len )) {
  150.       ++side;
  151.       p = p->prev;
  152.    }
  153.    side = (side & 1) ? RIGHT : LEFT;
  154.  
  155.  
  156.    /*
  157.     * when we wrap, we need know where the left margin is.
  158.     * let's look at the line above to see if this is the first line
  159.     * in a paragraph.
  160.     */
  161.    p = win->ll->prev;
  162.  
  163.    lm = find_left_margin( win->ll, mode.word_wrap );
  164.    rm = mode.right_margin;
  165.  
  166.    /*
  167.     * there two ways that words are pushed onto next line.
  168.     *  1. if the word being typed goes over the right margin
  169.     *  2. typing a word in the middle of the line pushes words at end of
  170.     *     line to next line
  171.     *
  172.     * if the user enters spaces past the right margin then we don't
  173.     *  word wrap spaces.
  174.     */
  175.    len = g_status.line_buff_len;
  176.    if (rcol > rm+1 && c != ' ') {
  177.  
  178.       /*
  179.        * if this is the first line in a paragraph then set left margin
  180.        *  to paragraph margin.
  181.        */
  182.       if ((p == NULL || is_line_blank( p->line, p->len )) &&
  183.            first_non_blank( (text_ptr)g_status.line_buff,
  184.                  g_status.line_buff_len ) > rm && mode.word_wrap == FIXED_WRAP)
  185.          lm = mode.parg_margin;
  186.  
  187.       /*
  188.        * simple word wrap.  the cursor goes past the right margin.
  189.        *  find the beginning of the word and put it on a new line.
  190.        *
  191.        * Special case - if the word begins at the left margin then
  192.        *  don't wrap it.
  193.        */
  194.       for (i=rcol-1; i > lm  &&  g_status.line_buff[i] != ' '; )
  195.          i--;
  196.       if (i > lm) {
  197.          i++;
  198.          win->rcol = i;
  199.          g_status.command = WordWrap;
  200.          insert_newline( win );
  201.          if (mode.right_justify == TRUE)
  202.             justify_right_margin( win, win->ll->prev,
  203.                  mode.word_wrap == FIXED_WRAP ? find_left_margin( win->ll->prev,
  204.                  mode.word_wrap ) : lm, rm, side );
  205.  
  206.          /*
  207.           * find out where to place the cursor on the new line.
  208.           */
  209.          win->rcol = lm + rcol - i;
  210.          check_virtual_col( win, win->rcol, win->rcol );
  211.  
  212.          /*
  213.           * we just wrapped the word at the eol.  now, let's see if
  214.           *  we can combine it with the line below.  since just added
  215.           *  a line, set new_line to false - don't add another line.
  216.           */
  217.  
  218.          len = find_end( win->ll->line, win->ll->len );
  219.          if (len < rm+1)
  220.             combine_wrap_spill( win, len, lm, rm, side, FALSE );
  221.       }
  222.    } else if (len > rm+1) {
  223.  
  224.       /*
  225.        * this is the second word wrap case.  we are pushing words onto
  226.        * next line.  we need to now what character is in the right margin.
  227.        *
  228.        * 1) if the character is not a space, then we need to search backwards
  229.        *    to find the start of the word that is on the right margin.
  230.        * 2) if the character is a space, then we need to search forward to
  231.        *    find the word that is over the right margin.
  232.        */
  233.  
  234.       /*
  235.        * don't wrap spaces past right margin
  236.        */
  237.       if (c == ' ' && rcol > rm) {
  238.